 /*******************************************************************************
  * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.internal.presentations;

 import java.util.ArrayList ;

 import org.eclipse.jface.action.IMenuManager;
 import org.eclipse.jface.action.MenuManager;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.util.Geometry;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.DisposeEvent;
 import org.eclipse.swt.events.DisposeListener;
 import org.eclipse.swt.events.MouseAdapter;
 import org.eclipse.swt.events.MouseEvent;
 import org.eclipse.swt.events.MouseListener;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.graphics.Rectangle;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Menu;
 import org.eclipse.swt.widgets.TabFolder;
 import org.eclipse.swt.widgets.TabItem;
 import org.eclipse.ui.IPropertyListener;
 import org.eclipse.ui.internal.IPreferenceConstants;
 import org.eclipse.ui.internal.WorkbenchPlugin;
 import org.eclipse.ui.presentations.IPresentablePart;
 import org.eclipse.ui.presentations.IStackPresentationSite;
 import org.eclipse.ui.presentations.PresentationUtil;
 import org.eclipse.ui.presentations.StackDropResult;
 import org.eclipse.ui.presentations.StackPresentation;

 /**
  * A stack presentation using native widgets.
  * <p>
  * EXPERIMENTAL
  * </p>
  *
  * @since 3.0
  */
 public class NativeStackPresentation extends StackPresentation {

     private TabFolder tabFolder;

     private Listener dragListener;

     private IPresentablePart current;

     private MenuManager systemMenuManager = new MenuManager();

     private static IPreferenceStore preferenceStore = WorkbenchPlugin.getDefault()
             .getPreferenceStore();

     // don't reset this dynamically, so just keep the information static.
 // see bug:
 // 75422 [Presentations] Switching presentation to R21 switches immediately, but only partially
 private static int tabPos = preferenceStore.getInt(IPreferenceConstants.VIEW_TAB_POSITION);
   
     private final static String TAB_DATA = NativeStackPresentation.class
             .getName()
             + ".partId"; //$NON-NLS-1$

     private MouseListener mouseListener = new MouseAdapter() {
         public void mouseDown(MouseEvent e) {
             // // PR#1GDEZ25 - If selection will change in mouse up ignore mouse down.
 // // Else, set focus.
 // TabItem newItem = tabFolder.getItem(new Point(e.x, e.y));
 // if (newItem != null) {
 // TabItem oldItem = tabFolder.getSelection();
 // if (newItem != oldItem)
 // return;
 // }
 if (current != null) {
                 current.setFocus();
             }
         }
     };

     private Listener menuListener = new Listener() {
         /* (non-Javadoc)
          * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
          */
         public void handleEvent(Event event) {
             Point pos = new Point(event.x, event.y);
             // TabItem item = tabFolder.getItem(pos);
 TabItem item = null;
             IPresentablePart part = null;
             if (item != null) {
                 part = getPartForTab(item);
             }
             showPaneMenu(part, pos);
         }
     };

     private Listener selectionListener = new Listener() {
         public void handleEvent(Event e) {
             IPresentablePart item = getPartForTab((TabItem) e.item);
             if (item != null) {
                 getSite().selectPart(item);
                 // item.setFocus();
 }
         }
     };

     private Listener resizeListener = new Listener() {
         public void handleEvent(Event e) {
             setControlSize();
         }
     };

     private IPropertyListener childPropertyChangeListener = new IPropertyListener() {
         public void propertyChanged(Object source, int property) {

             if (isDisposed()) {
                 return;
             }

             if (source instanceof IPresentablePart) {
                 IPresentablePart part = (IPresentablePart) source;
                 childPropertyChanged(part, property);
             }
         }
     };

     private DisposeListener tabDisposeListener = new DisposeListener() {
         public void widgetDisposed(DisposeEvent e) {
             if (e.widget instanceof TabItem) {
                 TabItem item = (TabItem) e.widget;
                 IPresentablePart part = getPartForTab(item);
                 part.removePropertyListener(childPropertyChangeListener);
             }
         }
     };

     public NativeStackPresentation(Composite parent,
             IStackPresentationSite stackSite) {
         super(stackSite);

         tabFolder = new TabFolder(parent, tabPos);

         // listener to switch between visible tabItems
 tabFolder.addListener(SWT.Selection, selectionListener);

         // listener to resize visible components
 tabFolder.addListener(SWT.Resize, resizeListener);

         // listen for mouse down on tab to set focus.
 tabFolder.addMouseListener(mouseListener);

         tabFolder.addListener(SWT.MenuDetect, menuListener);

         dragListener = new Listener() {
             public void handleEvent(Event event) {
                 Point localPos = new Point(event.x, event.y);
                 // TabItem tabUnderPointer = tabFolder.getItem(localPos);
 TabItem tabUnderPointer = null;

                 if (tabUnderPointer == null) {
                     return;
                 }

                 IPresentablePart part = getPartForTab(tabUnderPointer);

                 if (getSite().isPartMoveable(part)) {
                     getSite().dragStart(part, tabFolder.toDisplay(localPos),
                             false);
                 }
             }
         };

         PresentationUtil.addDragListener(tabFolder, dragListener);

     }

     /**
      * Returns the index of the tab for the given part, or returns tabFolder.getItemCount()
      * if there is no such tab.
      *
      * @param part part being searched for
      * @return the index of the tab for the given part, or the number of tabs
      * if there is no such tab
      */
     private final int indexOf(IPresentablePart part) {
         if (part == null) {
             return tabFolder.getItemCount();
         }

         TabItem[] items = tabFolder.getItems();

         for (int idx = 0; idx < items.length; idx++) {
             IPresentablePart tabPart = getPartForTab(items[idx]);

             if (part == tabPart) {
                 return idx;
             }
         }

         return items.length;
     }

     /**
      * Returns the tab for the given part, or null if there is no such tab
      *
      * @param part the part being searched for
      * @return the tab for the given part, or null if there is no such tab
      */
     protected final TabItem getTab(IPresentablePart part) {
         TabItem[] items = tabFolder.getItems();

         int idx = indexOf(part);

         if (idx < items.length) {
             return items[idx];
         }

         return null;
     }

     /**
      * @param part
      * @param property
      */
     protected void childPropertyChanged(IPresentablePart part, int property) {
         TabItem tab = getTab(part);
         initTab(tab, part);
     }

     protected final IPresentablePart getPartForTab(TabItem item) {
         IPresentablePart part = (IPresentablePart) item.getData(TAB_DATA);
         return part;
     }

     protected TabFolder getTabFolder() {
         return tabFolder;
     }

     public boolean isDisposed() {
         return tabFolder == null || tabFolder.isDisposed();
     }

     /**
      * Set the size of a page in the folder.
      */
     private void setControlSize() {
         if (current == null || tabFolder == null) {
             return;
         }
         // Rectangle bounds;
 // @issue as above, the mere presence of a theme should not change the behaviour
 // if ((mapTabToPart.size() > 1)
 // || ((tabThemeDescriptor != null) && (mapTabToPart.size() >= 1)))
 // bounds = calculatePageBounds(tabFolder);
 // else
 // bounds = tabFolder.getBounds();
 current.setBounds(calculatePageBounds(tabFolder));
         //current.moveAbove(tabFolder);
 }

     public static Rectangle calculatePageBounds(TabFolder folder) {
         if (folder == null) {
             return new Rectangle(0, 0, 0, 0);
         }
         Rectangle bounds = folder.getBounds();
         Rectangle offset = folder.getClientArea();
         bounds.x += offset.x;
         bounds.y += offset.y;
         bounds.width = offset.width;
         bounds.height = offset.height;
         return bounds;
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.internal.skins.Presentation#dispose()
      */
     public void dispose() {
         if (isDisposed()) {
             return;
         }
         PresentationUtil.removeDragListener(tabFolder, dragListener);

         //systemMenuManager.dispose();

         tabFolder.dispose();
         tabFolder = null;
     }

     private TabItem createPartTab(IPresentablePart part, int tabIndex) {
         TabItem tabItem = new TabItem(tabFolder, SWT.NONE, tabIndex);
         tabItem.setData(TAB_DATA, part);
         part.addPropertyListener(childPropertyChangeListener);
         tabItem.addDisposeListener(tabDisposeListener);
         initTab(tabItem, part);
         return tabItem;
     }

     /**
      * Initializes a tab for the given part. Sets the text, icon, tool tip,
      * etc. This will also be called whenever a relevant property changes
      * in the part to reflect those changes in the tab. Subclasses may override
      * to change the appearance of tabs for a particular part.
      *
      * @param tabItem tab for the part
      * @param part the part being displayed
      */
     protected void initTab(TabItem tabItem, IPresentablePart part) {
         tabItem.setText(part.getName());
         tabItem.setToolTipText(part.getTitleToolTip());

         Image tabImage = part.getTitleImage();
         if (tabImage != tabItem.getImage()) {
             tabItem.setImage(tabImage);
         }
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.internal.skins.StackPresentation#addPart(org.eclipse.ui.internal.skins.IPresentablePart, org.eclipse.ui.internal.skins.IPresentablePart)
      */
     public void addPart(IPresentablePart newPart, Object cookie) {
         createPartTab(newPart, tabFolder.getItemCount());
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.internal.skins.StackPresentation#removePart(org.eclipse.ui.internal.skins.IPresentablePart)
      */
     public void removePart(IPresentablePart oldPart) {
         TabItem item = getTab(oldPart);
         if (item == null) {
             return;
         }
         oldPart.setVisible(false);

         item.dispose();
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.internal.skins.StackPresentation#selectPart(org.eclipse.ui.internal.skins.IPresentablePart)
      */
     public void selectPart(IPresentablePart toSelect) {
         if (toSelect == current) {
             return;
         }

         if (current != null) {
             current.setVisible(false);
         }

         current = toSelect;

         if (current != null) {
             tabFolder.setSelection(indexOf(current));
             current.setVisible(true);
             setControlSize();
         }
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.internal.skins.Presentation#setBounds(org.eclipse.swt.graphics.Rectangle)
      */
     public void setBounds(Rectangle bounds) {
         tabFolder.setBounds(bounds);
         setControlSize();
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.internal.skins.Presentation#computeMinimumSize()
      */
     public Point computeMinimumSize() {
         return Geometry.getSize(tabFolder.computeTrim(0, 0, 0, 0));
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.internal.skins.Presentation#setVisible(boolean)
      */
     public void setVisible(boolean isVisible) {
         if (current != null) {
             current.setVisible(isVisible);
         }
         tabFolder.setVisible(isVisible);
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.internal.skins.Presentation#setState(int)
      */
     public void setState(int state) {
         // tabFolder.setMinimized(state == IPresentationSite.STATE_MINIMIZED);
 // tabFolder.setMaximized(state == IPresentationSite.STATE_MAXIMIZED);
 }

     /* (non-Javadoc)
      * @see org.eclipse.ui.internal.skins.Presentation#getSystemMenuManager()
      */
     public IMenuManager getSystemMenuManager() {
         return systemMenuManager;
     }

     /**
      * @param part
      * @param point
      */
     protected void showPaneMenu(IPresentablePart part, Point point) {
         systemMenuManager.update(false);
         Menu aMenu = systemMenuManager.createContextMenu(tabFolder.getParent());
         aMenu.setLocation(point.x, point.y);
         aMenu.setVisible(true);
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.internal.skins.Presentation#getControl()
      */
     public Control getControl() {
         return tabFolder;
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.internal.skins.StackPresentation#dragOver(org.eclipse.swt.widgets.Control, org.eclipse.swt.graphics.Point)
      */
     public StackDropResult dragOver(Control currentControl, Point location) {

         // Determine which tab we're currently dragging over
 // Point localPos = tabFolder.toControl(location);
 // final TabItem tabUnderPointer = tabFolder.getItem(localPos);
 final TabItem tabUnderPointer = null;

         // This drop target only deals with tabs... if we're not dragging over
 // a tab, exit.
 if (tabUnderPointer == null) {
             return null;
         }

         // return new StackDropResult(Geometry.toDisplay(tabFolder, tabUnderPointer.getBounds()),
 // tabFolder.indexOf(tabUnderPointer));
 return null;
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.presentations.StackPresentation#showSystemMenu()
      */
     public void showSystemMenu() {
         // TODO Auto-generated method stub

     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.presentations.StackPresentation#showPaneMenu()
      */
     public void showPaneMenu() {
         // TODO Auto-generated method stub

     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.presentations.StackPresentation#getTabList(IPresentablePart)
      */
     public Control[] getTabList(IPresentablePart part) {
         ArrayList list = new ArrayList ();
         if (getControl() != null) {
             list.add(getControl());
         }
         if (part.getToolBar() != null) {
             list.add(part.getToolBar());
         }
         if (part.getControl() != null) {
             list.add(part.getControl());
         }
         return (Control[]) list.toArray(new Control[list.size()]);
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.presentations.StackPresentation#getCurrentPart()
      */
     public IPresentablePart getCurrentPart() {
         return current;
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.presentations.StackPresentation#setActive(int)
      */
     public void setActive(int newState) {

     }

 }

